
import { Renderer, Camera, Transform, Texture, Program, Geometry, Mesh, Vec3 } from '../../';
import { Orbit } from '../../';

const vertex100 = /* glsl */ `
            attribute vec3 position;
            attribute vec3 barycentric;

            uniform mat4 modelViewMatrix;
            uniform mat4 projectionMatrix;

            varying vec3 vBarycentric;

            void main() {
                vBarycentric = barycentric;
                gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
            }
        `;

const fragment100 = /* glsl */ `#extension GL_OES_standard_derivatives : enable
            precision highp float;

            varying vec3 vBarycentric;

            void main() {
                vec3 bary = vBarycentric;

                vec3 color = vec3(0);
                float alpha = 1.0;

                // Line thickness - in pixels
                float width = 1.0 * 0.5;
                vec3 d = fwidth(bary);
                vec3 s = smoothstep(d * (width + 0.5), d * (width - 0.5), bary);
                alpha *= max(max(s.x, s.y), s.z);

                // Dashes
                alpha *= step(0.0, sin(max(bary.x, bary.y) * 3.14 * 5.0));

                // Back face shading
                color = mix(vec3(1, 0, 0), color, vec3(gl_FrontFacing));
                alpha = mix(alpha * 0.1 + 0.02, alpha, float(gl_FrontFacing));

                gl_FragColor.rgb = color;
                gl_FragColor.a = alpha;
            }
        `;

const vertex300 = /* glsl */ `#version 300 es
            in vec3 position;
            in vec3 barycentric;

            uniform mat4 modelViewMatrix;
            uniform mat4 projectionMatrix;

            out vec3 vBarycentric;

            void main() {
                vBarycentric = barycentric;
                gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
            }
        `;

const fragment300 = /* glsl */ `#version 300 es
            precision highp float;

            in vec3 vBarycentric;

            out vec4 FragColor;

            void main() {
                vec3 bary = vBarycentric;

                vec3 color = vec3(0);
                float alpha = 1.0;

                // Line thickness - in pixels
                float width = 1.0 * 0.5;
                vec3 d = fwidth(bary);
                vec3 s = smoothstep(d * (width + 0.5), d * (width - 0.5), bary);
                alpha *= max(max(s.x, s.y), s.z);

                // Dashes
                alpha *= step(0.0, sin(max(bary.x, bary.y) * 3.14 * 5.0));

                // Back face shading
                color = mix(vec3(1, 0, 0), color, vec3(gl_FrontFacing));
                alpha = mix(alpha * 0.1 + 0.02, alpha, float(gl_FrontFacing));

                FragColor.rgb = color;
                FragColor.a = alpha;
            }
        `;


const renderer = new Renderer({ dpr: 2 });
const gl = renderer.gl;
document.body.appendChild(gl.canvas);
gl.clearColor(1, 1, 1, 1);

const camera = new Camera(gl, { fov: 35 });
camera.position.set(3, 2, 4);

const controls = new Orbit(camera, {
    target: new Vec3(0, 1, 0),
});

function resize() {
    renderer.setSize(window.innerWidth, window.innerHeight);
    camera.perspective({ aspect: gl.canvas.width / gl.canvas.height });
}
window.addEventListener('resize', resize, false);
resize();

const scene = new Transform();

const program = new Program(gl, {
    vertex: renderer.isWebgl2 ? vertex300 : vertex100,
    fragment: renderer.isWebgl2 ? fragment300 : fragment100,
    transparent: true,
    cullFace: null,
    depthTest: false,
});

function addBarycentric(position) {
    const count = position.length / 9;
    const barycentric = [];

    for (let i = 0; i < count; i++) {
        if (i % 2 === 0) barycentric.push(0, 0, 1, 0, 1, 0, 1, 0, 0);
        else barycentric.push(0, 1, 0, 0, 0, 1, 1, 0, 0);
    }

    return new Float32Array(barycentric);
};

let mesh;
loadModel();
async function loadModel() {
    const data = await (await fetch(`assets/goat.json`)).json();

    const geometry = new Geometry(gl, {
        position: { size: 3, data: new Float32Array(data.position) },
        uv: { size: 2, data: new Float32Array(data.uv) },
        normal: { size: 3, data: new Float32Array(data.normal) },
        barycentric: { size: 3, data: addBarycentric(data.position) },
    });

    mesh = new Mesh(gl, { geometry, program });
    mesh.setParent(scene);
}

requestAnimationFrame(update);
function update() {
    requestAnimationFrame(update);

    controls.update();
    if (mesh) mesh.rotation.y += 0.005;
    renderer.render({ scene, camera });
}

document.getElementsByClassName('Info')[0].innerHTML = 'Wireframe Shader. Model by Google Poly';
document.title = 'OGL • Wireframe Shader';